﻿
namespace SRTSolutions.Elevate
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;

    /// <summary>
    /// Things that are missing from the string class.
    /// </summary>
    public static class StringExtensions
    {
        /// <summary>
        ///    Returns a value indicating whether the specified System.String object occurs
        ///    within this string.
        /// </summary>
        /// <param name="source">The string to search. (Haystack)</param>
        /// <param name="value">The string to seek. (Needle)</param>
        /// <param name="comparisonType"></param>
        /// <returns>true if the value parameter occurs within this string or if value is the empty string; otherwise, false</returns>
        /// <remarks>Exactly the same as string.Contains but has a StringComparison param.</remarks>
        public static bool Contains(this string source, string value, StringComparison comparisonType)
        {
            if (String.IsNullOrEmpty(source))
                throw new ArgumentException("source is null or empty.", "source");
            if (String.IsNullOrEmpty(value))
                throw new ArgumentException("value is null or empty.", "value");
            if (value == string.Empty) return true;
            return source.IndexOf(value, comparisonType) >= 0;
        }

        /// <summary>
        /// Returns a value indicating whether the string contains any digit characters.
        /// </summary>
        /// <param name="source">The string to search.</param>
        /// <returns>True if source contains a digit; otherwise, false.</returns>
        public static bool ContainsDigit(this string source)
        {
            return @"\d".Regex().IsMatch(source);
        }

        /// <summary>
        /// Looks for a number at the end of the string and if it finds it, increments it.
        /// </summary>
        /// <param name="source">The source string.</param>
        /// <returns>A new string with a new number.</returns>
        public static string IncrementTrailingNumber(this string source)
        {
            if (String.IsNullOrEmpty(source))
                throw new ArgumentException("source is null or empty.", "source");
            var match = System.Text.RegularExpressions.Regex.Match(source, @"(.*?)(\d+)$");
            return match.Groups[1].Value + (long.Parse(match.Groups[2].Value) + 1);

        }

        /// <summary>
        ///  Concatenates all the elements of a string array, using the specified separator between each element.
        /// </summary>
        /// <param name="source">contains the elements to concatenate.</param>
        /// <param name="separator">The string to use as a separator.</param>
        /// <returns>A string that consists of the elements in source delimited by the separator string.</returns>
        public static string Join(this IEnumerable<string> source, string separator)
        {
            if (source == null)
                throw new ArgumentNullException("source", "source is null.");
            if (null==separator)
                throw new ArgumentException("separator is null or empty.", "separator");
            return string.Join(separator, source.ToArray());
        }

        /// <summary>
        /// Get the Levenshtein Distance between the two strings.
        /// </summary>
        /// <param name="first"></param>
        /// <param name="second"></param>
        /// <returns></returns>
        public static int GetLevenshteinDistance(this string first, string second)
        {
            int m = first.Length+1;
            int n = second.Length+1;
            int[,] d = new int[m, n];
            for (int i = 0; i < m; i++)
                d[i, 0] = i;
            for (int j = 0; j < n; j++)
                d[0, j] = j;
            for (int j = 1; j < n; j++)
            {
                for (int i = 1; i < m; i++)
                {
                    if (first[i-1] == second[j-1])
                        d[i, j] = d[i - 1, j - 1];
                    else
                        d[i, j] = (new[] { d[i - 1, j] + 1, d[i, j - 1] + 1, d[i - 1, j - 1] + 1 }).Min();
                }
            }
            return d[m-1,n-1];
        }
        /// <summary>
        /// Return a new Regex object for the specified regular expression.
        /// </summary>
        /// <param name="regex"></param>
        /// <returns></returns>
        public static Regex Regex(this string regex)
        {
            return new Regex(regex);
        }

        /// <summary>
        /// Within a specified input string, replaces all strings that match a specified
        ///  regular expression with a specified replacement string.
        /// </summary>
        /// <param name="input">The string to search for a match.</param>
        /// <param name="pattern">The regular expression pattern to match.</param>
        /// <param name="replacement">The replacement string.</param>
        /// <returns>A new string that is identical to the input string, except that a replacement string takes the place of each matched string.
        /// </returns>
        /// <remarks>Often the extension method syntax is just nicer.
        /// </remarks>
        public static string RegexReplace(this string input, string pattern, string replacement)
        {
            if (null==input)
                throw new ArgumentNullException("input is null.", "input");
            if (String.IsNullOrEmpty(pattern))
                throw new ArgumentException("pattern is null or empty.", "pattern");
            if (String.IsNullOrEmpty(replacement))
                throw new ArgumentException("replacement is null or empty.", "replacement");
            return System.Text.RegularExpressions.Regex.Replace(input, pattern, replacement);
        }
    }
}
